package net.huashitong.service.money;

import jodd.util.StringUtil;
import net.huashitong.config.QRCodePayConfig;
import net.huashitong.service.sys.SsSysTableService;
import net.huashitong.ssydt.exceptions.ServiceException;
import net.huashitong.ssydt.money.constant.MoneyConsts;
import net.huashitong.ssydt.money.entity.*;
import net.huashitong.ssydt.money.entity.vo.OrderInVO;
import net.huashitong.ssydt.money.entity.vo.OrderOutVO;
import net.huashitong.ssydt.money.entity.vo.VipBagsVo;
import net.huashitong.ssydt.money.entity.vo.VipMyVO;
import net.huashitong.ssydt.provider.utils.date.DateUtils;
import net.huashitong.ssydt.security.utils.Sha1Util;
import net.huashitong.ssydt.security.utils.ValidUtils;
import net.huashitong.wxpay.RequestHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author shaoxian.zhong
 * @create 2018-06-25 20:10
 */
@Service
public class MoneyServiceImpl implements MoneyService {
    private static final String GOODS_TYPE_ERROR = "商品类型错误";
    @Autowired
    private QRCodePayConfig qrCodePayConfig;

    private static final String ALREADY_PAY_ORDER = "您已支付该订单";
    @Autowired
    private SsMoneyVipBagService ssMoneyVipBagService;
    @Autowired
    private SsMoneyVipService ssMoneyVipService;
    @Autowired
    private SsMoneyOrderService ssMoneyOrderService;
    @Autowired
    private ChatPayService weChatPayService;
    @Autowired
    private SsMoneyVipRecordService ssMoneyVipRecordService;
    @Autowired
    private SsMoneyOrderDetailService ssMoneyOrderDetailService;
    @Autowired
    private SsMoneyGoldBagService ssMoneyGoldBagService;

    @Autowired
    private SsSysTableService ssSysTableService;

    private Logger logger = LoggerFactory.getLogger(MoneyServiceImpl.class);

    private static final long DAY_MILLISECOND = 86400000L;

    @Override
    public VipMyVO vipMy(String userId) {
        boolean isVip = false;
        Date gmtEnd = new Date(System.currentTimeMillis());
        String vipState="02";//未开通
        SsMoneyVip ssMoneyVip = ssMoneyVipService.getByUserId(userId);
        if (ssMoneyVip != null) {
            vipState="03";//过期
            //转成日期字符比较，只对天敏感
            String nowDateStr = DateUtils.formatDate(gmtEnd, "yyyyMMdd");
            String gmtEndStr = DateUtils.formatDate(ssMoneyVip.getGmtEnd(), "yyyyMMdd");
            if (nowDateStr.compareTo(gmtEndStr) <= 0) {
                vipState="01"; //开通
                isVip = true;
                gmtEnd = ssMoneyVip.getGmtEnd();

            }
        }
        VipMyVO vipMyVO = new VipMyVO();
        vipMyVO.setGmtEnd(gmtEnd);
        vipMyVO.setVip(isVip);
        vipMyVO.setEndTime(DateUtils.formatDate(gmtEnd, "yyyy年MM月dd日"));
        vipMyVO.setVipState(vipState);
        return vipMyVO;
    }

    @Override
    public List<VipBagsVo> vipBags() {
        List<SsMoneyVipBag> ssMoneyVipBags = ssMoneyVipBagService.queryByState();
        List<VipBagsVo> list = new ArrayList<>();
        for (SsMoneyVipBag ssMoneyVipBag : ssMoneyVipBags) {
            //排除苹果vip套餐
            if (StringUtil.isBlank(ssMoneyVipBag.getAppleGoodsId())) {
                VipBagsVo vipBagsVo = new VipBagsVo(ssMoneyVipBag);
                list.add(vipBagsVo);
            }
        }
        return list;
    }

    @Override
    public List<VipBagsVo> vipBagsByAppType(String appType) {
        List<SsMoneyVipBag> ssMoneyVipBags = ssMoneyVipBagService.queryByAppType(appType);
        List<VipBagsVo> list = new ArrayList<>();
        for (SsMoneyVipBag ssMoneyVipBag : ssMoneyVipBags) {
            VipBagsVo vipBagsVo = new VipBagsVo(ssMoneyVipBag);
            list.add(vipBagsVo);
        }
        return list;
    }

    @Override
    public OrderOutVO orders(OrderInVO orderInVO, String userId) {
        ValidUtils.validTerminal(orderInVO.getTerminal());//客户端类型校验
        //生产订单id
        String orderId = ssSysTableService.updateMaxId("t_ss_money_order");
        //生成商品
        List<OrderInVO.Goods> goodses = orderInVO.getGoodses();
        List<SsMoneyOrderDetail> ssMoneyOrderDetails = new ArrayList<>();
        for (OrderInVO.Goods goods : goodses) {
            //商品购买限制校验
            validGoodsLimit(goods, userId);
            SsMoneyOrderDetail ssMoneyOrderDetail = new SsMoneyOrderDetail();
            this.setUnitPriceAndGoodName(goods, ssMoneyOrderDetail);
            ssMoneyOrderDetail.setOrderId(orderId);
            ssMoneyOrderDetail.setGoodsId(goods.getGoodsId());
            ssMoneyOrderDetail.setNumber(goods.getNumber());
            ssMoneyOrderDetail.setGoodsType(goods.getGoodsType());
            ssMoneyOrderDetails.add(ssMoneyOrderDetail);
        }

        //生成订单
        SsMoneyOrder ssMoneyOrder = new SsMoneyOrder();
        ssMoneyOrder.setOrderId(orderId);
        ssMoneyOrder.setUserId(userId);
        this.setOrderPriceAndOrdrName(ssMoneyOrder, ssMoneyOrderDetails);
        ssMoneyOrder.setOrderState(MoneyConsts.OrderState.UNPAID);
        ssMoneyOrder.setPayAccount("");
        ssMoneyOrder.setTerminal(orderInVO.getTerminal());
        ssMoneyOrder.setDeviceCode(orderInVO.getDeviceCode());
        ssMoneyOrder.setDeviceType(orderInVO.getDeviceType());
        ssMoneyOrder.setDeviceOperation(orderInVO.getDeviceOperation());
        ssMoneyOrder.setClientVersion(orderInVO.getClientVersion());
        ssMoneyOrderService.save(ssMoneyOrder);//保存订单
        ssMoneyOrderDetailService.batchSave(ssMoneyOrderDetails);//批量保存商品

        return new OrderOutVO(ssMoneyOrder);
    }

    /**
     * 设置订单价格(总价保留2位小数，多余位数直接舍去)，
     * 设置订单名称
     *
     * @param ssMoneyOrder
     * @param ssMoneyOrderDetails
     */
    private void setOrderPriceAndOrdrName(SsMoneyOrder ssMoneyOrder, List<SsMoneyOrderDetail> ssMoneyOrderDetails) {
        BigDecimal totalPrice = new BigDecimal(0);
        List<String> orderNames = new ArrayList<>();
        for (SsMoneyOrderDetail ssMoneyOrderDetail : ssMoneyOrderDetails) {
            BigDecimal number = new BigDecimal(ssMoneyOrderDetail.getNumber());
            BigDecimal goodsPrice = ssMoneyOrderDetail.getUnitPrice().multiply(number);
            totalPrice = totalPrice.add(goodsPrice);
            orderNames.add(ssMoneyOrderDetail.getGoodsName());
        }
        String orderName;
        if (orderNames.size() > 1) {
            orderName = String.format("%s等商品", orderNames.get(0));
        } else {
            orderName = orderNames.get(0);
        }
        ssMoneyOrder.setOrderName(orderName);
        ssMoneyOrder.setOrderPrice(totalPrice.setScale(2, BigDecimal.ROUND_DOWN));
    }

    /**
     * 设置单价和商品价格
     *
     * @param goods
     * @param ssMoneyOrderDetail
     */
    private void setUnitPriceAndGoodName(OrderInVO.Goods goods, SsMoneyOrderDetail ssMoneyOrderDetail) {
        BigDecimal unitPrice = null;
        String goodsName = null;
        //判断商品类型，根据类型取商品信息
        switch (goods.getGoodsType()) {
            case MoneyConsts.GoodsType.VIP_BAG:
                SsMoneyVipBag ssMoneyVipBag = ssMoneyVipBagService.getById(goods.getGoodsId());
                unitPrice = this.getGoodsPrice(ssMoneyVipBag);
                goodsName = ssMoneyVipBag.getBagName();
                break;
            case MoneyConsts.GoodsType.GOLD_BAG:
                SsMoneyGoldBag ssMoneyGoldBag = ssMoneyGoldBagService.getById(goods.getGoodsId());
                unitPrice = this.getGoodsPrice(ssMoneyGoldBag);
                goodsName = ssMoneyGoldBag.getBagName();
                break;
            case MoneyConsts.GoodsType.GOODS:
                //暂时无普通商品
                throw new ServiceException(GOODS_TYPE_ERROR);
            default:
                throw new ServiceException(GOODS_TYPE_ERROR);
        }
        ssMoneyOrderDetail.setUnitPrice(unitPrice);
        ssMoneyOrderDetail.setGoodsName(goodsName);
    }

    /**
     * 获取商品价格
     *
     * @param basePriceEntity
     * @return
     */
    private BigDecimal getGoodsPrice(BasePriceEntity basePriceEntity) {
        BigDecimal price;
        switch (basePriceEntity.getNowExecute()) {
            case MoneyConsts.NowExecute.ORIGINA_PRICE:
                price = basePriceEntity.getOriginalPrice();
                break;
            case MoneyConsts.NowExecute.FAVOURABLE_PRICE:
                price = basePriceEntity.getFavourablePrice();
                break;
            case MoneyConsts.NowExecute.PREFERENCE_PRICE:
                price = basePriceEntity.getPreferencePrice();
                break;
            default:
                price = basePriceEntity.getOriginalPrice();
                break;
        }
        return price;
    }

    /**
     * 购买次数限制处理
     *
     * @param goods  OrderInVO.Goods 商品对象
     * @param userId
     */
    private void validGoodsLimit(OrderInVO.Goods goods, String userId) {
        switch (goods.getGoodsType()) {
            case MoneyConsts.GoodsType.VIP_BAG:
                validVipBagNumberLimit(goods, userId);
                break;
            case MoneyConsts.GoodsType.GOLD_BAG:
                validGoldBagNumberLimit(goods, userId);
                break;
            case MoneyConsts.GoodsType.GOODS:
                //暂时无普通商品
                throw new ServiceException("暂时无普通商品");
            default:
                throw new ServiceException(GOODS_TYPE_ERROR);
        }

    }

    private void validGoldBagNumberLimit(OrderInVO.Goods goods, String userId) {
        SsMoneyGoldBag ssMoneyGoldBag = ssMoneyGoldBagService.getById(goods.getGoodsId());
        if (ssMoneyGoldBag == null) {
            throw new ServiceException(String.format("金币套餐不存在，id [%d]", goods.getGoodsId()));
        }
        if (ssMoneyGoldBag.getNumberLimit() > 0) {
            validNumberLimit(userId, goods, ssMoneyGoldBag.getNumberLimit());
        }
    }

    /**
     * VIP购买次数限制
     *
     * @param goods
     * @param userId
     */
    private void validVipBagNumberLimit(OrderInVO.Goods goods, String userId) {
        SsMoneyVipBag ssMoneyVipBag = ssMoneyVipBagService.getById(goods.getGoodsId());
        if (ssMoneyVipBag == null) {
            throw new ServiceException(String.format("VIP套餐不存在，id [%d]", goods.getGoodsId()));
        }
        if (ssMoneyVipBag.getNumberLimit() > 0) {
            validNumberLimit(userId, goods, ssMoneyVipBag.getNumberLimit());
        }
    }

    /**
     * 次数检验
     *
     * @param userId
     * @param goods
     * @param numberLimit
     */
    private void validNumberLimit(String userId, OrderInVO.Goods goods, int numberLimit) {
        boolean isBig = goods.getNumber() > numberLimit;
        if (isBig) {
            throw new ServiceException("下单失败，原因：超过购买次数限制。");
        } else {
            List<SsMoneyOrderDetail> ssMoneyOrderDetails = ssMoneyOrderDetailService
                    .queryJoinOrderByUserIdWithGoodsIdWithGoodsType(userId, goods.getGoodsId(), goods.getGoodsType());
            int number = 0;
            for (SsMoneyOrderDetail ssMoneyOrderDetail : ssMoneyOrderDetails) {
                number += ssMoneyOrderDetail.getNumber();
            }
            if (number >= numberLimit) {
                throw new ServiceException("下单失败，原因：超过购买次数限制。");
            }
        }
    }

    //公众号支付
    @Override
    public TreeMap<String, String> payForWeChat(String orderId, HttpServletRequest request, HttpServletResponse response) throws Exception {
        SsMoneyOrder ssMoneyOrder = ssMoneyOrderService.getByOrderId(orderId);
        if (ssMoneyOrder == null) {
            throw new ServiceException("订单不存在");
        }

        //防止重复处理订单
        if (MoneyConsts.OrderState.PAID.equals(ssMoneyOrder.getOrderState())) {
            throw new ServiceException(ALREADY_PAY_ORDER);
        }
        return weChatPayService.unifiedOrderForWeChat(ssMoneyOrder, request, response);
    }

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void payCallback(SsMoneyOrder order) {
        SsMoneyOrder ssMoneyOrder = this.ssMoneyOrderService.getByOrderId(order.getOrderId());
        if (ssMoneyOrder == null) {
            throw new ServiceException(String.format("订单不存在，orderId: [%s]", order.getOrderId()));
        }
        List<SsMoneyOrderDetail> ssMoneyOrderDetails = ssMoneyOrderDetailService
                .queryByOrderId(ssMoneyOrder.getOrderId());
        if (ssMoneyOrderDetails == null || ssMoneyOrderDetails.isEmpty()) {
            throw new ServiceException(String.format("订单不存在在商品，orderId: [%s]", order.getOrderId()));
        }
        for (SsMoneyOrderDetail ssMoneyOrderDetail : ssMoneyOrderDetails) {
            switch (ssMoneyOrderDetail.getGoodsType()) {
                case MoneyConsts.GoodsType.VIP_BAG:
                    vipBagGoodsHandler(ssMoneyOrder, ssMoneyOrderDetail);
                    break;
                case MoneyConsts.GoodsType.GOODS:
                    //暂时无普通商品
                    throw new ServiceException("暂时无普通商品");
                default:
                    throw new ServiceException(GOODS_TYPE_ERROR);
            }
        }
    }

    /**
     * 处理购买vip套餐包
     *
     * @param ssMoneyOrder
     * @param ssMoneyOrderDetail
     */
    private void vipBagGoodsHandler(SsMoneyOrder ssMoneyOrder, SsMoneyOrderDetail ssMoneyOrderDetail) {
        SsMoneyVipBag ssMoneyVipBag = ssMoneyVipBagService.getById(ssMoneyOrderDetail.getGoodsId());
        if (ssMoneyVipBag == null) {
            logger.error("vip套餐包不存在，订单号[{}]，订单明细号[{}]",
                    ssMoneyOrder.getOrderId(), ssMoneyOrderDetail.getId());
            throw new ServiceException("vip套餐包不存在");
        }

        Date nowDate = new Date(System.currentTimeMillis());
        Date recordGmtStart = nowDate;
        VipMyVO vipMyVO = vipMy(ssMoneyOrder.getUserId());
        if (vipMyVO.isVip()) {
            recordGmtStart = vipMyVO.getGmtEnd();
        }
        Map<String, Object> map = getGmtEndAndEffectiveDay(recordGmtStart, ssMoneyVipBag, ssMoneyOrderDetail);
        Date vipGmtEnd = (Date) map.get("gmtEnd");
        //变更vip信息
        SsMoneyVip ssMoneyVip = ssMoneyVipService.getByUserId(ssMoneyOrder.getUserId());
        if (ssMoneyVip == null) {
            ssMoneyVip = new SsMoneyVip();
            ssMoneyVip.setUserId(ssMoneyOrder.getUserId());
            ssMoneyVip.setGmtStart(nowDate);
            ssMoneyVip.setGmtEnd(vipGmtEnd);
            ssMoneyVipService.save(ssMoneyVip);
        } else {
            if (!vipMyVO.isVip()) {
                ssMoneyVip.setGmtStart(nowDate);
            }
            ssMoneyVip.setGmtEnd(vipGmtEnd);
            ssMoneyVipService.updateSelective(ssMoneyVip);
        }

        //保存vip开通记录
        SsMoneyVipRecord ssMoneyVipRecord = new SsMoneyVipRecord();
        ssMoneyVipRecord.setUserId(ssMoneyOrder.getUserId());
        ssMoneyVipRecord.setVipBagId(ssMoneyVipBag.getId());
        ssMoneyVipRecord.setGmtStart(recordGmtStart);
        ssMoneyVipRecord.setGmtEnd(vipGmtEnd);
        ssMoneyVipRecord.setGmtBuy(nowDate);
        ssMoneyVipRecord.setOrderId(ssMoneyOrder.getOrderId());
        ssMoneyVipRecord.setRemarks("");
        ssMoneyVipRecord.setEffectiveDay((Integer) map.get("effectiveDay"));
        ssMoneyVipRecordService.save(ssMoneyVipRecord);
    }

    /**
     * 获取vip到期时间和有效天数
     *
     * @param recordGmtStart     vip记录的开始时间
     * @param ssMoneyVipBag
     * @param ssMoneyOrderDetail
     * @return
     */
    private Map<String, Object> getGmtEndAndEffectiveDay(Date recordGmtStart,
                                                         SsMoneyVipBag ssMoneyVipBag, SsMoneyOrderDetail ssMoneyOrderDetail) {
        Date gmtEnd = new Date(System.currentTimeMillis());
        Integer effectiveDay = 0;
        switch (ssMoneyVipBag.getBagType()) {
            case MoneyConsts.BagType.EFFECTIVE_DAYS:
                effectiveDay = ssMoneyVipBag.getBagDay() * ssMoneyOrderDetail.getNumber();
                long millisecond = DAY_MILLISECOND * effectiveDay;
                gmtEnd = new Date(recordGmtStart.getTime() + millisecond);
                break;
            case MoneyConsts.BagType.DEADLINE:
                long time = ssMoneyVipBag.getGmtExpiryDate().getTime() - System.currentTimeMillis();
                if (time > 0 && time <= DAY_MILLISECOND) {
                    effectiveDay = 1;
                    gmtEnd = new Date(recordGmtStart.getTime() + DAY_MILLISECOND);
                } else if (time > DAY_MILLISECOND) {
                    long dayTemp = (time / DAY_MILLISECOND);
                    effectiveDay = (int) ((time % DAY_MILLISECOND == 0) ? dayTemp : (dayTemp + 1));
                    gmtEnd = new Date(recordGmtStart.getTime() + (DAY_MILLISECOND * effectiveDay));
                }
                break;
            default:
                throw new ServiceException("vip套餐包，套餐类型错误");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("gmtEnd", gmtEnd);
        map.put("effectiveDay", effectiveDay);
        return map;
    }
    /**
     * 网站发起微信支付(扫码）
     *
     * @param orderId
     * @param userId
     * @param request
     * @param response
     * @throws Exception
     * @author: huiyang.yu
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public Map<String, String> payWebForWx(String orderId, String userId, HttpServletRequest request, HttpServletResponse response){
        TreeMap<String, String> outParams = new TreeMap<String, String>();
        SsMoneyOrder order = ssMoneyOrderService.getByOrderId(orderId);
        if (order == null) {
            outParams.put("error", "订单不存在");
            return outParams;
        }
        if (order.getOrderState().equals(SsMoneyOrder.orderState.PAYMENT)) {
            outParams.put("error", "订单已完成支付");
            return outParams;
        }

        RequestHandler reqHandler = new RequestHandler(request, response);
        // 初始化
        reqHandler.init();
        reqHandler.init(qrCodePayConfig.getAppID(), qrCodePayConfig.getKey(), qrCodePayConfig.getMchID(), qrCodePayConfig.getNotifyUrl());
        Integer money = order.getOrderPrice().multiply(new BigDecimal(100)).intValue();//单位为分
//		Integer money = 1;//单位为分
        String entity = reqHandler.WebgenProductArgs(
                "华仕通教育-" + order.getOrderName(),
                order.getOrderId(),


                request.getRemoteAddr(),
                money.toString(),
                Sha1Util.getNonceStr());

        Map<String, String> map = reqHandler.unifiedorder(entity);
        if (map.get("return_code").equals("SUCCESS")) {
            outParams.put("code_url", map.get("code_url"));
            outParams.put("money", String.valueOf(order.getOrderPrice()));
        } else {
            outParams.put("error", "发起微信支付失败，请联系客服");
        }
        return outParams;
    }



}
